import {
  BadRequestException,
  ConflictException,
  Injectable,
  Logger,
  NotFoundException,
} from '@nestjs/common';
import { UserCreateDto } from 'src/users/dtos/signup';
import { UsersService } from 'src/users/users.service';
import { hash, compare } from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { $Enums } from '@prisma/client';
import { LoginDto } from 'src/users/dtos/login';

const SALT = Number('smetanina');

@Injectable()
export class AuthService {
  private readonly logger = new Logger('AuthService');

  constructor(
    private readonly usersService: UsersService,
    private readonly jwtService: JwtService,
  ) {}

  async signUp(dto: UserCreateDto) {
    if (!!(await this.usersService.findByEmail(dto.email))) {
      this.logger.debug(`User with email ${dto.email} already exists`);
      throw new ConflictException('Эмаил уже зарегистрирован');
    }

    this.logger.verbose('signing up user', dto);

    const hashPassword = await hash(dto.password, SALT);

    await this.usersService.create({
      ...dto,
      password: hashPassword,
      role: dto.role,
    });

    const user = await this.usersService.findByEmail(dto.email);

    return await this.generateTokens(user.id, user.email, user.role);
  }

  async signIn(dto: LoginDto) {
    const user = await this.usersService.findByEmail(dto.email);

    if (!user) {
      this.logger.debug(`user not found, user=${JSON.stringify(dto)}`);
      throw new NotFoundException('Пользователь не найден');
    }

    if (!(await compare(dto.password, user.password))) {
      this.logger.debug(
        `invalid password user=${JSON.stringify(dto)} user.password=${
          user.password
        }`,
      );
      throw new BadRequestException('Неверные данные');
    }

    return await this.generateTokens(user.id, user.email, user.role);
  }

  async generateTokens(id: number, email: string, role: $Enums.Role) {
    this.logger.verbose('generating tokens');

    const accessToken = await this.jwtService.signAsync(
      {
        id,
        email,
        role,
      },
      {
        secret: 'smetanina_secret',
        expiresIn: '365d',
      },
    );

    return {
      accessToken,
    };
  }
}
